/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using MyPhotoIndex.Interfaces;
using System.Reflection;
using System.IO;
using MyPhotoIndex.Utilities;
using MyPhotoIndex.Interfaces.ImageFormatProviders;
using System.Xml;

namespace MyPhotoIndex.Plugins.ImageFormatProviders
{
    public sealed class ImageFormatProviders : IEnumerable<IImageFormatProvider>
    {
        private static ImageFormatProviders m_instance;
        private static MissingImageFormatProvider m_missingFormatProvider = new MissingImageFormatProvider();

        private Dictionary<string, IImageFormatProvider> m_providers;
        private List<IImageFormatProvider> m_providersList;

        private ImageFormatProviders()
        {
            m_providers = new Dictionary<string, IImageFormatProvider>();
            m_providersList = new List<IImageFormatProvider>();
        }

        public static ImageFormatProviders Default
        {
            get
            {
                if (m_instance != null)
                {
                    return m_instance;
                }

                lock (typeof(ImageFormatProviders))
                {
                    if (m_instance != null)
                    {
                        return m_instance;
                    }

                    ImageFormatProviders instance = new ImageFormatProviders();

                    string path = Path.Combine(ApplicationFolders.ProvidersFolder, "MyPhotoIndex.Plugins.ImageFormatProviders.config");

                    using (XmlTextReader reader = new XmlTextReader(path))
                    {
                        if (reader.ReadToFollowing(typeof(ImageFormatProviders).Name) == true)
                        {
                            if (reader.ReadToFollowing("provider") == true)
                            {
                                while (true)
                                {
                                    string extention = string.Empty;
                                    string assemblyName = string.Empty;
                                    string typeName = string.Empty;

                                    if (reader.MoveToFirstAttribute() == true)
                                    {
                                        while (true)
                                        {
                                            if (string.Compare(reader.Name, "extention", true) == 0)
                                            {
                                                extention = reader.Value;
                                            }
                                            else
                                                if (string.Compare(reader.Name, "type", true) == 0)
                                                {
                                                    string[] values = reader.Value.Split(new char[] { ',' });
                                                    typeName = values[0];
                                                    if (values.Length > 1)
                                                    {
                                                        assemblyName = values[1];
                                                    }
                                                }

                                            if (reader.MoveToNextAttribute() == false)
                                            {
                                                break;
                                            }
                                        }
                                    }

                                    if (string.IsNullOrEmpty(typeName) == false &&
                                        string.IsNullOrEmpty(extention) == false)
                                    {

                                        Assembly asm = null;

                                        try
                                        {
                                            if (string.IsNullOrEmpty(assemblyName) == false)
                                            {
                                                asm = Assembly.Load(assemblyName);
                                            }
                                            else
                                            {
                                                asm = Assembly.GetExecutingAssembly();
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Logger.Log(ex);
                                        }

                                        if (asm != null)
                                        {
                                            Type type = asm.GetType(typeName);
                                            ConstructorInfo con = type.GetConstructor(new Type[] { typeof(string) });
                                            if (con == null)
                                            {
                                                Logger.Log(string.Format("Provider {0} does not have a valid constructor {0}(string}", type.Name));
                                                continue;
                                            }

                                            IImageFormatProvider provider = (IImageFormatProvider)con.Invoke(new Object[] { extention });

                                            string lowerExtention = extention.ToLower();
                                            instance.m_providers.Add(lowerExtention, provider);
                                            instance.m_providers.Add("." + lowerExtention, provider);
                                            instance.m_providersList.Add(provider);
                                        }
                                    }

                                    if (reader.ReadToNextSibling("provider") == false)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    m_instance = instance;

                    return m_instance;
                }
            }
        }

        public IImageFormatProvider this[string extention]
        {
            get
            {
                try
                {
                    return m_providers[extention.ToLower()];
                }
                catch (KeyNotFoundException)
                {
                    return m_missingFormatProvider;
                }
            }
        }

        public string[] SupportedImageExtentions
        {
            get
            {
                List<string> extentions = new List<string>();
                foreach (string extention in m_providers.Keys)
                {
                    if (extention.StartsWith(".") == false)
                    {
                        extentions.Add(extention);
                    }
                }

                return extentions.ToArray();
            }
        }

        public string ImporterFilterFormat
        {
            get
            {
                string filter = string.Empty;
                foreach (string extention in m_providers.Keys)
                {
                    if (extention.StartsWith(".") == false)
                    {
                        filter += string.Format("*.{0};", extention);
                    }
                }

                return filter;
            }
        }

        #region IEnumerable<IImageFormatProvider> Members

        public IEnumerator<IImageFormatProvider> GetEnumerator()
        {
            return m_providersList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }

    internal class ExtentionComparer : IEqualityComparer<string>
    {
        #region IEqualityComparer<string> Members

        public bool Equals(string x, string y)
        {
            return (string.Compare(x, y, true) == 0);
        }

        public int GetHashCode(string obj)
        {
            return obj.GetHashCode();
        }

        #endregion
    }
}
